﻿using MediatR;
using Microsoft.EntityFrameworkCore;
using global::B.S.Data.MES.API.Applications.CangKu.Command;
using global::B.S.Requst;
using B.S.Infratrctrue;
using B.S.Domain.CangKu;

namespace B.S.Data.MES.API.Applications.CangKu.CommandHandlers
{
    /// <summary>
    /// 出库处理：支持批次出库、出库编号唯一校验、同步 ERP ChuKuInfo
    /// </summary>
    public class ChuKuCommandHandler : IRequestHandler<ChuKuCommand, APIRequst<int>>
    {
        private readonly IBaseRepository<RuKuinfo> _ruKuRepo;
        private readonly IBaseRepository<RukuinfoLog> _rukuLogRepo;
        private readonly IHttpClientFactory _httpClientFactory;

        public ChuKuCommandHandler(
            IBaseRepository<RuKuinfo> ruKuRepo,
            IBaseRepository<RukuinfoLog> rukuLogRepo,
            IHttpClientFactory httpClientFactory)
        {
            _ruKuRepo = ruKuRepo;
            _rukuLogRepo = rukuLogRepo;
            _httpClientFactory = httpClientFactory;
        }

        public async Task<APIRequst<int>> Handle(ChuKuCommand request, CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(request.Code))
                return new APIRequst<int> { Code = RequstCode.失败, Msg = "商品编码为空" };

            if (request.Batches == null || !request.Batches.Any())
                return new APIRequst<int> { Code = RequstCode.失败, Msg = "批次信息不能为空" };

            // 请求内编号去重
            var outNos = request.Batches.Select(b => b.OutNo).ToList();
            if (outNos.Any(string.IsNullOrWhiteSpace))
                return new APIRequst<int> { Code = RequstCode.失败, Msg = "每个批次必须提供出库编号 OutNo" };

            if (outNos.Count != outNos.Distinct().Count())
                return new APIRequst<int> { Code = RequstCode.失败, Msg = "请求内存在重复的出库编号" };

            var db = _ruKuRepo.db;

            // 校验请求总数量是否不超过现有库存（RuKuinfo 中相同 SID 的库存之和）
            var ruKuRecords = await db.Set<RuKuinfo>()
                .Where(r => r.SID == request.Code)
                .OrderBy(r => r.RuKuId)
                .ToListAsync(cancellationToken);

            var totalAvailable = ruKuRecords.Sum(r => r.ProductCount);
            var totalRequest = request.Batches.Sum(b => b.Count);
            if (totalRequest <= 0)
                return new APIRequst<int> { Code = RequstCode.失败, Msg = "出库总数量必须大于0" };

            if (totalAvailable < totalRequest)
                return new APIRequst<int> { Code = RequstCode.失败, Msg = "库存不足，无法出库" };

            // 检查数据库中是否已有相同的出库编号（使用 RukuinfoLog 的 RukuName 字段，格式 "出库-{OutNo}"）
            var logNamesToCheck = outNos.Select(n => $"出库-{n}").ToList();
            var existsLogs = await db.Set<RukuinfoLog>()
                .Where(l => logNamesToCheck.Contains(l.RukuName))
                .Select(l => l.RukuName)
                .ToListAsync(cancellationToken);

            if (existsLogs.Any())
            {
                return new APIRequst<int> { Code = RequstCode.失败, Msg = $"以下出库编号已被使用：{string.Join(",", existsLogs)}" };
            }

            using var transaction = await db.Database.BeginTransactionAsync(cancellationToken);
            try
            {
                // 将每个批次数量从 RuKuinfo 中扣减（从早的记录开始扣），并记录出库日志
                var remainingPerBatch = new Queue<int>(request.Batches.Select(b => b.Count));
                var batchOutNos = new Queue<string>(request.Batches.Select(b => b.OutNo));

                // We'll iterate ruKuRecords and deduct until all batches fulfilled
                // For logging and ERP sync we'll collect per-batch info
                var batchList = request.Batches.ToList();

                // Deduct across ruKuRecords
                int batchIndex = 0;
                foreach (var batch in batchList)
                {
                    int need = batch.Count;
                    for (int i = 0; i < ruKuRecords.Count && need > 0; i++)
                    {
                        var r = ruKuRecords[i];
                        if (r.ProductCount <= 0) continue;

                        int deduct = Math.Min(need, r.ProductCount);
                        r.ProductCount -= deduct;
                        need -= deduct;

                        // mark modified
                        db.Set<RuKuinfo>().Update(r);
                    }

                    if (need > 0)
                    {
                        // should not happen because we checked totals, but safety
                        throw new InvalidOperationException("分配库存失败：可用库存不足以完成分批扣减。");
                    }

                    // 添加出库日志（使用现有 RukuinfoLog）
                    var log = new RukuinfoLog
                    {
                        RukuName = $"出库-{batch.OutNo}",
                        Date = DateTime.Now
                    };
                    db.Set<RukuinfoLog>().Add(log);

                    batchIndex++;
                }

                // 保存库存变更与日志
                await db.SaveChangesAsync(cancellationToken);

                // 同步到 ERP API：对每个批次调用一次 ERP 接口，通知增加出库数量（或让 ERP 扣减入库）
                // 下面为示例 URL 和 payload，请根据实际 ERP 接口调整
                var client = _httpClientFactory.CreateClient();
                client.BaseAddress = new Uri("http://localhost:5199/"); // TODO: 修改为实际 ERP 地址或从配置读取

                foreach (var batch in batchList)
                {
                    var payload = new
                    {
                        SID = request.Code,
                        ProductCount = batch.Count,
                        OutNo = batch.OutNo
                    };

                    // 示例 POST 到 ERP API，请根据实际接口修改路径和返回处理
                    var resp = await client.PostAsJsonAsync("/api/WarehouseDealiy/IncreaseChuKuCount", payload, cancellationToken);
                    if (!resp.IsSuccessStatusCode)
                    {
                        // 回滚并报错
                        throw new Exception($"同步ERP失败，HTTP {(int)resp.StatusCode}");
                    }
                }

                await transaction.CommitAsync(cancellationToken);
                return new APIRequst<int> { Code = RequstCode.成功, Msg = "出库成功" };
            }
            catch (Exception ex)
            {
                try { await transaction.RollbackAsync(cancellationToken); } catch { }
                return new APIRequst<int> { Code = RequstCode.失败, Msg = $"出库失败：{ex.Message}" };
            }
        }
    }
}
